package fechas;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import excepciones.FormatException;

/**
 * Se encarga de trabajar con fechas. Convierte de String a Date, calcula cual
 * fue primero y la diferencia entre ellas.
 * 
 * @author grupo 2
 * 
 */
public class FechaUtils {

	// EXPRESIONES REGULARES PARA LA VALIDACION DE LAS FECHAS
	private static final String regexLatino = "(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/((19|20)\\d\\d)";
	private static final String regexLatinoReducido = "(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/(\\d\\d)";
	private static final String regexAmericano = "(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])-((19|20)\\d\\d)";
	private static final String regexIso8601 = "((19|20)\\d\\d)-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])";

	/**
	 * Convierte el string que representa una fecha, del formato Latino
	 * (dd/MM/yyyy) al tipo Date. En caso de error lanza una Exception*
	 * 
	 * @param String
	 *            fecha
	 * @return Date
	 */

	public static Date stringToDateLatino(String fecha) {
		try {
			validarFormato(fecha, regexLatino);
			DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
			return formatter.parse(fecha);
		} catch (Exception e) {

			e.printStackTrace();
		}
		return null;
	}
	
	public static boolean isFechaLatino(String fecha){
		try{
			validarFormato(fecha, regexLatinoReducido);
		}
		catch(FormatException e){
			return false;
		}
		return true;
	}
	
	public static Date stringToDateLatinoReducido(String fecha) {
		try {
			validarFormato(fecha, regexLatinoReducido);
			DateFormat formatter = new SimpleDateFormat("dd/MM/yy");
			return formatter.parse(fecha);
		} catch (Exception e) {

			e.printStackTrace();
		}
		return null;
	}	

	/**
	 * Convierte el string que representa una fecha, del formato Americano
	 * (MM-dd-yyyy) al tipo Date. En caso de error lanza una Exception*
	 * 
	 * @param String
	 *            fecha
	 * @return Date
	 */
	public static Date stringToDateAmericano(String fecha) {
		try {
			// valido que ingrese una fecha correspondiente a patron;
			validarFormato(fecha, regexAmericano);
			DateFormat formatter = new SimpleDateFormat("MM-dd-yyyy");
			return formatter.parse(fecha);
		} catch (Exception e) {
			e.printStackTrace();

		}

		return null;

	}

	/**
	 * Convierte el string que representa una fecha, del formato ISO
	 * (yyyy-MM-dd)al tipo Date. En caso de error lanza una Exception
	 * 
	 * @param String
	 *            fecha
	 * @return Date
	 */
	public static Date stringToDateIso8606(String fecha) {
		try {
			validarFormato(fecha, regexIso8601);
			DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
			return formatter.parse(fecha);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Convierte el string que representa una fecha, de un formato desconocido
	 * al tipo Date. En caso de error notifica a la consola y devuelve null
	 * 
	 * @param String
	 *            fecha
	 * @return Date
	 */
	public static Date stringToDateFlexible(String fecha) {
		try {
			if (fecha.matches(regexLatino))
				return stringToDateLatino(fecha);
			else if (fecha.matches(regexAmericano))
				return stringToDateAmericano(fecha);
			else if (fecha.matches(regexIso8601))
				return stringToDateIso8606(fecha);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Calcula la diferencia en dias entre dos fechas ingresadas como String en
	 * un formato compatible en caso de Error lanza una exception y devuelve -1
	 * 
	 * @param fechaUno
	 *            String
	 * @param fechaDos
	 *            String
	 * @return Diferencia
	 */
	public static long diferenciaEntreFechasEnDias(String fechaUno,
			String fechaDos) {
		try {
			Date primerFecha = FechaUtils.stringToDateFlexible(fechaUno);
			Date segundaFecha = FechaUtils.stringToDateFlexible(fechaDos);

			long diferencia = (Math.abs(primerFecha.getTime()
					- segundaFecha.getTime()) / 86400000);
			System.out.println("La diferencia de dias entre " + fechaUno
					+ " y " + fechaDos + " es " + diferencia);
			return diferencia;
		} catch (Exception e) {
			e.printStackTrace();
		}

		return -1;

	}

	/**
	 * Calcula la duracion del intervalo entendido entre dos fechas.
	 * 
	 * @param fechaFinal
	 * @param fechaInicial
	 * @return
	 */
	public static Date duracionIntervalo(Date fechaFinal, Date fechaInicial) {
		long duracion = fechaFinal.getTime() - fechaInicial.getTime();
		return new Date(duracion);
	}

	/**
	 * 
	 * Devuelve 1 si la primera fecha es anterior a la segunda 0 si es falso -1
	 * si hay error
	 * 
	 * @param fechaUno
	 *            String
	 * @param fechaDos
	 *            String
	 * @return Bool
	 */
	public static boolean esFechaAnterior(String fechaUno, String fechaDos) {
		Date primerFecha = null, segundaFecha = null;

		try {
			primerFecha = FechaUtils.stringToDateFlexible(fechaUno);
			segundaFecha = FechaUtils.stringToDateFlexible(fechaDos);

			if (primerFecha != null && segundaFecha != null) {
				if (primerFecha.getTime() < segundaFecha.getTime()) {
					System.out.println("Es verdadero");
					return true;
				} else {
					System.out.println("Es falso");
					return false;
				}

			}

		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("Hubo un error");
		}
		return false;

	}

	private static void validarFormato(String fecha, String expReg)
			throws FormatException {
		if (!fecha.matches(expReg))
			throw new FormatException(fecha);

	}

	/**
	 * Recibe una fecha y la hora en Strings por separado y las convierte a un
	 * solo ojeto Date
	 * @param fecha
	 * @param hhmm
	 * @return
	 */

	@SuppressWarnings("deprecation")
	public static Date fechaConHorasYMinutos(String fecha, String hhmm) {
		Date fechaDate = FechaUtils.stringToDateLatino(fecha);
		fechaDate.setHours(Integer.valueOf(hhmm.substring(0, 2)));
		fechaDate.setMinutes(Integer.valueOf(hhmm.substring(3, 5)));
		return fechaDate;
	}

	/**
	 * Compara 2 fechas por Año, mes y dia.
	 * 
	 * @param fecha1
	 * @param fecha2
	 * @return 0 si son iguales
	 */
	public static int comparar(Date fecha1, Date fecha2) {
		Calendar c1 = Calendar.getInstance();
		c1.setTime(fecha1);
		Calendar c2 = Calendar.getInstance();
		c2.setTime(fecha2);
		if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR))
			return c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR);
		if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH))
			return c1.get(Calendar.MONTH) - c2.get(Calendar.MONTH);
		return c1.get(Calendar.DAY_OF_MONTH) - c2.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * Devuelve una nueva fecha con la cantHoras agregadas a la fecha pasada por
	 * parametro
	 * 
	 * @param fecha
	 * @param cantHoras
	 * @return
	 */
	public static Date addHours(Date fecha, Integer cantHoras) {
		Calendar cal = Calendar.getInstance(); // creates calendar
		cal.setTime(fecha); // sets calendar time/date
		cal.add(Calendar.HOUR_OF_DAY, cantHoras); // adds one hour
		return cal.getTime();
	}

}
